package org.jeecg;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.*;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringUtils;
import org.jeecg.modules.system.controller.UrlController;

/**
 * Created by liudh on 2020/8/30.
 */
public class RSADemo {
    public static final String   PARAM_SIGN        = "sign";
    public static final String   PARAM_STARTWITH   = "t_";
    public static final String   serialVersionUID  = "serialVersionUID";
    public static final String   PARAM_SPLIT       = "|";
    private static final String  ALGORITHM         = "RSA";

    /**
     * RSA最大加密明文大小
     */
    private static final int     MAX_ENCRYPT_BLOCK = 117;

    /**
     * 获取需要签名的数据,未进行MD5
     *
     * @param map 参数集合
     * @return
     * @create  2020年2月8日 下午2:00:35 luochao
     * @history
     */
    public static String getSignParams(Map<String, String> map) {
        // 根据KEY排序
        Map<String, String> sortedParamMap = new TreeMap<>();
        for (Map.Entry<String, String> entry : map.entrySet()) {
            //略过sign、serialVersionUID、以t_开头的参数
            if (entry.getKey().equalsIgnoreCase(PARAM_SIGN) || entry.getKey().toLowerCase().startsWith(PARAM_STARTWITH)
                    || entry.getKey().equalsIgnoreCase(serialVersionUID)) {
                continue;
            }
            sortedParamMap.put(entry.getKey(), entry.getValue().toString());
        }
        // 最终结果
        List<String> allList = new LinkedList<String>();
        for (String value : sortedParamMap.values()) {
            if (StringUtils.isNotEmpty(value)) {
                allList.add(value);
            }
        }
        return StringUtils.join(allList.iterator(), PARAM_SPLIT);
    }

    /**
     * 私钥加密
     *
     * @param data
     * @param privateKey
     * @return
     * @throws Exception
     * @create  2020年1月15日 下午7:55:08 luochao
     * @history
     */
    public static String encryptByPrivateKey(String data, String privateKey) throws Exception {
        byte[] decodeBase64Data = data.getBytes();
        byte[] decodeBase64Key = Base64.decodeBase64(privateKey.getBytes());
        PKCS8EncodedKeySpec pKCS8EncodedKeySpec = new PKCS8EncodedKeySpec(decodeBase64Key);
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
        PrivateKey key = keyFactory.generatePrivate(pKCS8EncodedKeySpec);
        return encrypt(key, decodeBase64Data);
    }

    /**
     * 分段加密
     *
     * @param key 加密key
     * @param bytes 被加密字节数组
     * @return
     * @throws NoSuchAlgorithmException
     * @throws NoSuchPaddingException
     * @throws InvalidKeyException
     * @throws IllegalBlockSizeException
     * @throws BadPaddingException
     * @throws IOException
     * @create  2020年1月15日 上午11:28:15 luochao
     * @history
     */
    private static String encrypt(Key key, byte[] bytes) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
            IllegalBlockSizeException, BadPaddingException, IOException {
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, key);
        int inputLength = bytes.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        byte[] encryptedData;
        try {
            int offset = 0;
            byte[] cache;
            int i = 0;
            while (inputLength - offset > 0) {
                if (inputLength - offset > MAX_ENCRYPT_BLOCK) {
                    cache = cipher.doFinal(bytes, offset, MAX_ENCRYPT_BLOCK);
                } else {
                    cache = cipher.doFinal(bytes, offset, inputLength - offset);
                }
                out.write(cache, 0, cache.length);
                i++;
                offset = i * MAX_ENCRYPT_BLOCK;
            }
            encryptedData = out.toByteArray();
        } finally {
            out.close();
        }

        return new String(Base64.encodeBase64(encryptedData));
    }

    /**
     *对字符串进行md5,各个语言均有md5
     *
     * @param str
     * @return
     * @create  2020年2月18日 下午4:11:01 luochao
     * @history
     */
    public static String md5(String str) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            //原因在于汉字编码，在加密时设置一下编码UTF-8，问题解决。
            md.update(str.getBytes("UTF-8"));
            byte b[] = md.digest();
            int i;
            StringBuffer buf = new StringBuffer("");
            for (int offset = 0; offset < b.length; offset++) {
                i = b[offset];
                if (i < 0)
                    i += 256;
                if (i < 16)
                    buf.append("0");
                buf.append(Integer.toHexString(i));
            }
            str = buf.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return str;
    }

    public static void main(String[] args) throws Exception {
//        Map<String, String> map = new HashMap<String, String>();
//        //自定义参数，项目中以实际为准
//        map.put("openid", "123456789");
//        map.put("callBackUrl", "https://webapp.lsmart.wang/card/card_home.shtml");
//        //开发者应用id,由云马开放平台提供,纯粹测试接口不用修改此参数, 实际开发中请修改为实际值
//        map.put("ymAppId", "2008261705489006");
//        String signParams = md5(getSignParams(map));
//        String sign = encryptByPrivateKey(signParams,
//                "MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAkmDeetdEnvMJ1qegkJzJDJwr wJHTgrYlcX1FkoNLe4XWN4265PoWXvlVU9TFe3/hBOB4El2b1jWSFoWc6FOoBwIDAQABAkAZ Aj3gpPjPY1yx9O/E5VSgN+ptuzx036PkEPAbCR2TW9XkssTrrRfACcU+hQ4K9B2CvMP9p82CpW vOk7Id30VxAiEA7ZJ5WehA1e29Zski7Ut1mL3oWdywvyLAMA3QZSDV3y8CIQCdu4n/B+Fvg8m EfsyJMeNzLA2GNH222h8zcFAOEE1OqQIhAN3lyvzkBvMKPLcttTbJHYzODKEqldfhQHth270pXz o3AiAWALExSDIkUifsOZvij3kA+eYxEGVw+mBb1pD0RUXjcQIhAOFSyREFyZIQz19+mckUC3AAF UKUS4cpuv5vcQgAD/Su");
//        System.out.println("sign:" + sign);
//
//        System.out.println("https://open.lsmart.wang/routeauth/auth/route/authorize/third/login?ymAppId=" + map.get("ymAppId") + "&callBackUrl=https://webapp.lsmart.wang/card/card_home.shtml&openid=" + map.get("openid") + "&sign=" + sign);
//        UrlController urlController = new UrlController();
//        urlController.getYiktczjl("A1401038");

        System.out.println(String.format("%04d", 123));
    }

}
